package system

import (
	"context"
	"github.com/mojocn/base64Captcha"
	"go.uber.org/zap"
	"server/global"
	"time"
)

const (
	CaptchaStoreMemory = "memory"
	CaptchaStoreRedis  = "redis"
)

var CaptchaServiceApp = new(CaptchaService).SetStore(CaptchaStoreRedis)

type CaptchaService struct {
	Store base64Captcha.Store
}

// CaptchaRedisStore redis存储
type CaptchaRedisStore struct {
	Expiration time.Duration
	PreKey     string
	Context    context.Context
}

// SetStore 设置验证码存储驱动
func (cap *CaptchaService) SetStore(t string) *CaptchaService {
	switch t {
	case CaptchaStoreMemory:
		cap.Store = base64Captcha.DefaultMemStore
	case CaptchaStoreRedis:
		cap.Store = &CaptchaRedisStore{
			Expiration: time.Second * 180,
			PreKey:     "captcha:",
			Context:    context.Background(),
		}
	}
	return cap
}

// Generate 验证码生成服务
func (cap *CaptchaService) Generate() (id, b64s string, err error) {
	// 字符,公式,验证码配置
	// 生成默认数字的driver
	driver := base64Captcha.NewDriverDigit(global.GvaConfig.Captcha.ImgHeight, global.GvaConfig.Captcha.ImgWidth, global.GvaConfig.Captcha.KeyLong, 0.7, 80)
	cp := base64Captcha.NewCaptcha(driver, cap.Store)
	return cp.Generate()
}

// 验证输入是否正确
func (cap *CaptchaService) Verify(id, answer string, clear bool) bool {
	return cap.Store.Verify(id, answer, clear)
}

//设置值
func (rs *CaptchaRedisStore) Set(id string, value string) error {
	err := global.GvaRedis.Set(rs.Context, rs.PreKey+id, value, rs.Expiration).Err()
	if err != nil {
		global.GvaLog.Error("RedisStoreSetError!", zap.Error(err))
		return err
	}
	return nil
}

//获取值
func (rs *CaptchaRedisStore) Get(key string, clear bool) string {
	val, err := global.GvaRedis.Get(rs.Context, key).Result()
	if err != nil {
		global.GvaLog.Error("RedisStoreGetError!", zap.Error(err))
		return ""
	}
	if clear {
		err := global.GvaRedis.Del(rs.Context, key).Err()
		if err != nil {
			global.GvaLog.Error("RedisStoreClearError!", zap.Error(err))
			return ""
		}
	}
	return val
}

//验证
func (rs *CaptchaRedisStore) Verify(id, answer string, clear bool) bool {
	key := rs.PreKey + id
	v := rs.Get(key, clear)
	return v == answer
}
